﻿using K9Nano.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Logging;

namespace K9Nano.AspNetCore.Authorization;

public class K9RbacRequirementHandler : AuthorizationHandler<K9RbacRequirement>
{
    private readonly IRbacChecker _rbacChecker;
    private readonly ILogger _logger;

    public K9RbacRequirementHandler(ILogger<K9RbacRequirementHandler> logger, IRbacChecker rbacChecker)
    {
        _rbacChecker = rbacChecker;
        _logger = logger;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, K9RbacRequirement requirement)
    {
        if (context.User.Identity?.IsAuthenticated != true)
        {
            context.Fail();
            return Task.CompletedTask;
        }

        if (context.Resource is not HttpContext httpContext)
        {
            context.Fail();
            return Task.CompletedTask;
        }

        var endpoint = httpContext.GetEndpoint();
        if (endpoint is null)
        {
            context.Fail();
            _logger.LogError("无法获取请求节点信息");
            return Task.CompletedTask;
        }

        var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
        if (actionDescriptor is null)
        {
            _logger.LogError("无法获取请求描述信息");
            context.Fail();
            return Task.CompletedTask;
        }

        var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? [];
        if (authorizeData.Any(a => a.Policy != RbacOptions.Policy))
        {
            // 由其他授权处理
            context.Succeed(requirement);
            return Task.CompletedTask;
        }
        try
        {

            var primaryId = actionDescriptor.ToActionPrimaryId();

            /* 检查用户权限 */
            if (_rbacChecker.Validate(primaryId))
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }
            _logger.LogWarning("当前用户 {User} 无权访问 {Resource}", context.User.Identity.Name, primaryId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "RBAC检查失败");
        }
        context.Fail();
        return Task.CompletedTask;
    }
}